package cn.hnu.utils;

import lombok.SneakyThrows;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

public class JwtUtils {
  // 公钥
  public final static String PUBLIC_JSON = "{\"kty\":\"RSA\",\"n\":\"tcX_mznjZqKecW-NE5jHYytd8LJIfronrb0m6Oc-dyuXPEgimyEuzFbh_l9N7MVEaeR4LIpO_dwye-kT1M8vhzSyT2M5HN9rcM_kPJOA_74KxDdd2O6akcKnRbPHGpWcjea7T0Idq4P9sjeW1kSsnn4yhp0CeoaP2esNLq-0TCqncIAt7ay3dkPfacb2vorCD-InsMG43nm9mylWCpwOI_pV4TUpb1agc5TQyCWzVY7A29rpwxdu1lh4jqOIY-X0FggfzxVzPGkHDtdiuZvNxEHOCs-gsDD2Kr7wQzj-I2FMq68li34qrUVlV8DDxqEay5OPmsPPCOVFaUdy9yM6ew\",\"e\":\"AQAB\"}";
  // 私钥
  public final static String PRIVATE_JSON = "{\"kty\":\"RSA\",\"n\":\"tcX_mznjZqKecW-NE5jHYytd8LJIfronrb0m6Oc-dyuXPEgimyEuzFbh_l9N7MVEaeR4LIpO_dwye-kT1M8vhzSyT2M5HN9rcM_kPJOA_74KxDdd2O6akcKnRbPHGpWcjea7T0Idq4P9sjeW1kSsnn4yhp0CeoaP2esNLq-0TCqncIAt7ay3dkPfacb2vorCD-InsMG43nm9mylWCpwOI_pV4TUpb1agc5TQyCWzVY7A29rpwxdu1lh4jqOIY-X0FggfzxVzPGkHDtdiuZvNxEHOCs-gsDD2Kr7wQzj-I2FMq68li34qrUVlV8DDxqEay5OPmsPPCOVFaUdy9yM6ew\",\"e\":\"AQAB\",\"d\":\"GPDQDQbeK5IgMPVQLe0BB_Db2gTu9dW_UFM17a_zk1tboWL5E0BJe7Jnc2-1MUmx2jZbF4AUrY1TL0rq3ytcXJiqPJf4g_x9xplSZM4NCEoVj8L_Bp8FKKnE1MdW3XrDY878Srg0z6NJIcpce7gpgoeokW16o8AnKGHcHwNEYaIfQR3dmVmiimop28txW6ngX6gnmompvkodg_IoIvlONuVCbUM3OWfNqU-qd873tvKdZpNNxLKsV_C6y2rizERRYxyM97exlqDhe59pRg2Uh5EirP3PpaFpvYhpY0IABDiQ-leLCGiaGL8jErtgQ9Bl4bl8VADFy_ka873eDFee8Q\",\"p\":\"yBxmX7GBcz3jM19syeOlqlujkTHzVmLBr_5FLVbdQnsMj1KxKjgMnqpITUWw0xUO8AtDjAGRm2tTxDu1UMgDBYt4ymel3yumiYYpjQlCwvib67ppXEjzw5B31Gq25XbJdbTCmuDdeuZvQsoGjU6HtcePJCP8jv7r6c_-8uBYvEs\",\"q\":\"6Ip_UONts9i9K5VwhiGq3gKfyxnZ-lgeEs1P_4DhxiyABIAXhlsd5__bBwYeedm-lcwk7dzDxNpRFKQAQX4uJdl20Io_xkuELqtX5NI-nZozpPWS07u11IcTYLGYDXXkU3tnqQ8MjTbyRIfXKBT_ePgY4M9IEdEiH4TRqCTdPJE\",\"dp\":\"EoG14hG7hBnsIjsoB3_bOWciOHJjK9EUUp90bF4FNnnEzph6NApc-GuNJkBUuyDOcdrI03Dts274n0RaX28wAFpGwIlXaM1TqJJU02tQ1lFBskpaJiPFD4gT3PxFj_EtbopaGRLEyPH4xjeC5ZympmQfU9tUJzFiRgxrarDe5AM\",\"dq\":\"pGPUYWCF2xArmzYH2CrQ2iXMxQ2_dST6DZyrIxr_gNNQpN3Qw6CCYdIUCsEeplFyU_9_U9AvbWhQzWCq9aG4CfXT8tTpBMu55Cwo9JBUx6GNRN5-L8SRZG8hGcgyj8F56jJhM7h5zRK87gmB5soBWIk7PSIL9tx7XQDOHioBZKE\",\"qi\":\"nTT3O2IG3n1JtCBGAuL5D2AHJ0iya7oPoQkwj4R9ozvBtPwJ6tYiRkyqW5Ja3Ypu5xarHsux2uXcu-oKOAe4nA5wu9PHrYQ9WI4HFdbRvKDBLvGeN64W1Vm9aLkEs8nFG6trPfC6cRFiy643fKxq2HyMtLvOXoSDMzxCcOCpi7k\"}";


  /**
   * 生成token
   *
   * @param userId    用户id
   * @param username 用户名字
   * @return
   */
  @SneakyThrows
  public static String sign(Long userId, String username, Integer roleId) {
    // 1、 创建jwtclaims  jwt内容载荷部分
    JwtClaims claims = new JwtClaims();
    // 是谁创建了令牌并且签署了它
    claims.setIssuer("hubery");
    // 令牌将被发送给谁
    claims.setAudience("audience");
    // 失效时间长 （分钟）
    claims.setExpirationTimeMinutesInTheFuture(60 * 24);
    // 令牌唯一标识符
    claims.setGeneratedJwtId();
    // 当令牌被发布或者创建现在
    claims.setIssuedAtToNow();
    // 再次之前令牌无效
    claims.setNotBeforeMinutesInThePast(2);
    // 主题
    claims.setSubject("exam");
    // 可以添加关于这个主题得声明属性
    claims.setClaim("userId", userId);
    claims.setClaim("username", username);
    claims.setClaim("roleId", roleId);


    // 2、签名
    JsonWebSignature jws = new JsonWebSignature();
    //赋值载荷
    jws.setPayload(claims.toJson());


    // 3、jwt使用私钥签署
    PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(PRIVATE_JSON)).getPrivateKey();
    jws.setKey(privateKey);


    // 4、设置关键 kid
    jws.setKeyIdHeaderValue("keyId");


    // 5、设置签名算法
    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    // 6、生成jwt
    String jwt = jws.getCompactSerialization();
    return jwt;
   }




  /**
   * 解密token，获取token中的信息
   *
   * @param token
   */
  @SneakyThrows
  public static Map<String, Object> verify(String token){
    // 1、引入公钥
    PublicKey publicKey = new RsaJsonWebKey(JsonUtil.parseJson(PUBLIC_JSON)).getPublicKey();
    // 2、使用jwtcoonsumer  验证和处理jwt
    JwtConsumer jwtConsumer = new JwtConsumerBuilder()
         .setRequireExpirationTime() //过期时间
         .setAllowedClockSkewInSeconds(30) //允许在验证得时候留有一些余地 计算时钟偏差  秒
         .setRequireSubject() // 主题生命
         .setExpectedIssuer("hubery") // jwt需要知道谁发布得 用来验证发布人
         .setExpectedAudience("audience") //jwt目的是谁 用来验证观众
         .setVerificationKey(publicKey) // 用公钥验证签名  验证密钥
         .setJwsAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.RSA_USING_SHA256))
         .build();
    // 3、验证jwt 并将其处理为 claims
    try {
      JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
      return jwtClaims.getClaimsMap();
     }catch (Exception e){
      return new HashMap();
     }
   }


  /**
   * 验证token是否有效
   * @param token
   * @return
   */
  public static boolean validateToken(String token){
     Map<String, Object> verify = verify(token);
     return verify.get("userId") != null;
   }




  public static void main(String[] args){
    // 生成
    String hubery = sign(1001L, "hubery",1);
    System.out.println(hubery);


    Map<String, Object> stringObjectMap = verify(hubery);
    System.out.println(stringObjectMap.get("userId"));
   }
}
